#ifndef Timer_h__
#define Timer_h__

namespace inf {

    /*
    ===============================================================================

    Clock tick counter. Should only be used for profiling.

    ===============================================================================
    */

    class Timer {
    public:
        enum timerState_t {
            TS_STARTED,
            TS_STOPPED
        };

    public:
        Timer( void );
        Timer( double elapsed );
        virtual			~Timer( void );

        Timer			operator+( const Timer &t ) const;
        Timer			operator-( const Timer &t ) const;
        Timer &		    operator+=( const Timer &t );
        Timer &		    operator-=( const Timer &t );

        void			start( void );
        void			stop( void );
        void			clear( void );
        double			clock_ticks( void ) const;
		double			delta_clock_ticks( void ) const;
		double			delta_sec( void ) const;
        timerState_t	get_state( void ) const;

    private:
        static double	base;
		double			ticksPerSec;
        double			startTict;
        double			clockTicks;
		double			delta;
        timerState_t	state;

        void			init_base_clock_ticks( void ) const;
    };


    /*
    =================
    Timer::Timer
    =================
    */
    INF_INLINE Timer::Timer( void ) {
        state = TS_STOPPED;
        clockTicks = 0.0;
		ticksPerSec = inf::sys->ClockTicksPerSecond();
    }

    /*
    =================
    Timer::Timer
    =================
    */
    INF_INLINE Timer::Timer( double elapsed ) {
        state = TS_STOPPED;
        clockTicks = elapsed;
    }

    /*
    =================
    Timer::~Timer
    =================
    */
    INF_INLINE Timer::~Timer( void ) {
    }

    /*
    =================
    Timer::operator+
    =================
    */
    INF_INLINE Timer Timer::operator+( const Timer &t ) const {
        assert( state == TS_STOPPED && t.state == TS_STOPPED );
        return Timer( clockTicks + t.clockTicks );
    }

    /*
    =================
    Timer::operator-
    =================
    */
    INF_INLINE Timer Timer::operator-( const Timer &t ) const {
        assert( state == TS_STOPPED && t.state == TS_STOPPED );
        return Timer( clockTicks - t.clockTicks );
    }

    /*
    =================
    Timer::operator+=
    =================
    */
    INF_INLINE Timer &Timer::operator+=( const Timer &t ) {
        assert( state == TS_STOPPED && t.state == TS_STOPPED );
        clockTicks += t.clockTicks;
        return *this;
    }

    /*
    =================
    Timer::operator-=
    =================
    */
    INF_INLINE Timer &Timer::operator-=( const Timer &t ) {
        assert( state == TS_STOPPED && t.state == TS_STOPPED );
        clockTicks -= t.clockTicks;
        return *this;
    }


    /*
    =================
    Timer::start
    =================
    */
    INF_INLINE void Timer::start( void ) {
        assert( state == TS_STOPPED );
        state = TS_STARTED;
        startTict = inf::sys->GetClockTicks();
    }

    /*
    =================
    Timer::stop
    =================
    */
    INF_INLINE void Timer::stop( void ) {
        assert( state == TS_STARTED );
        delta = (inf::sys->GetClockTicks() - startTict);
        clockTicks += delta;
        if ( base < 0.0 ) {
            init_base_clock_ticks();
        }
        if ( clockTicks > base ) {
            clockTicks -= base;
        }
        state = TS_STOPPED;
    }

    /*
    =================
    Timer::clear
    =================
    */
    INF_INLINE void Timer::clear( void ) {
        clockTicks = 0.0;
    }

    /*
    =================
    Timer::clock_ticks
    =================
    */
    INF_INLINE double Timer::clock_ticks( void ) const {
        assert( state == TS_STOPPED );
        return clockTicks;
    }

	INF_INLINE double Timer::delta_clock_ticks( void ) const {
		assert( state == TS_STOPPED );
		return delta;
	}

	INF_INLINE double Timer::delta_sec( void ) const {
		assert( state == TS_STOPPED );
		return delta / ticksPerSec;
	}

    /*
    ===============
    state
    ===============
    */
    INF_INLINE Timer::timerState_t Timer::get_state( void ) const { 
        return state;
    }

    class TimeReport {
    public:
        TimeReport();
        ~TimeReport();

        void			SetReportName( const char *name );
        int             AddReport( const char *name );
        Timer*          FindTimer( const char* name );
        Timer*          GetTimer( int index );

        void			Clear( void );
        void			Reset( void );
        void			AddTime( const char *name, Timer *time );

    private:
        List<Timer*>    timers;
        StrList		        names;
        Str                 name;
    };

}   // ::inf

#endif // Timer_h__